package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;


@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SpecParamService specParamService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    //分页查询商品spu
    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
//        SELECT * from tb_spu WHERE saleable = TRUE AND cid3 = 76 AND brand_id = 8557
//          #AND id = 12
//          LIMIT 0,3

        Page<Spu> spuPage = this.query()
                .eq(saleable != null, "saleable", saleable)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(id != null, "id", id)
                .page(new Page<>(page, rows));

        long total = spuPage.getTotal();//总记录数
        long totalPage = spuPage.getPages();//总页数
        List<Spu> spuList = spuPage.getRecords();//当前页的数据
        List<SpuDTO> spuDTOList = SpuDTO.convertEntityList(spuList);

        //SpuDTO中还有两个属性categoryName和brandName需要查询
        for (SpuDTO spuDTO : spuDTOList) {
            handleBrandAndCategoryName(spuDTO);
        }

        //转DTO
        return new PageDTO<>(total, totalPage, spuDTOList);
    }

    //新增商品
    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {

        //保存数据到spu表
        Spu spu = spuDTO.toEntity(Spu.class);
        //（前端传参缺少saleable）填充属性，默认下架
        spu.setSaleable(false);
        boolean success = this.save(spu);
        if (!success){
            throw new LyException(500,"新增商品失败");
        }

        //保存数据到spu_detail表
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
        //填充属性
        spuDetail.setSpuId(spu.getId());
        success = spuDetailService.save(spuDetail);
        if (!success){
            throw new LyException(500,"新增商品详情失败");
        }

        //保存多组数据到sku表
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        //创建集合，保存多个sku对象
        List<Sku> skuList = new ArrayList<>(skuDTOList.size());
        for (SkuDTO skuDTO : skuDTOList) {
            Sku sku = skuDTO.toEntity(Sku.class);
            // 填充属性
            sku.setSaleable(false);
            sku.setSpuId(spu.getId());
            sku.setSold(0L);

            skuList.add(sku);
        }
        //批量保存
        skuService.saveBatch(skuList);

    }

    //修改商品上下架
    @Override
    @Transactional
    public void updateSpuSaleable(Long spuId, Boolean saleable) {
        //更改spu表中的saleable
        boolean success = this.update()
                .set("saleable", saleable)
                .eq("id", spuId)
                .update();
        if (!success){
            throw new LyException(500,"修改商品上下架失败");
        }
        //更改sku表中的saleable
        success = skuService.update()
                .set("saleable", saleable)
                .eq("spu_id", spuId)
                .update();
        if (!success){
            throw new LyException(500,"修改商品上下架失败");
        }

        //商品微服务发送消息  mq生产者
        //根据商品上下架状态设置不同的路由key
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME,routingKey,spuId);
    }

    //编辑下架的商品前 回显数据
    //根据商品id查询商品的spu、sku、spuDetail等信息
    @Override
    public SpuDTO queryGoodsById(Long id) {

        //1.查询spu
        Spu spu = this.getById(id);
        if (spu == null){
            throw new LyException(400,"商品id不存在！");
        }
        //设置属性并创建对象
        SpuDTO spuDTO = new SpuDTO(spu);

        //2.查询sku
        List<Sku> skuList = skuService
                .query()
                .eq("spu_id", id)
                .list();
        if (CollectionUtils.isEmpty(skuList)){
            throw new LyException(400,"商品id不存在！");
        }
        //转DTO
        List<SkuDTO> skuDTOList = SkuDTO.convertEntityList(skuList);
        //设置属性
        spuDTO.setSkus(skuDTOList);

        //3.查询spuDetail
        SpuDetail spuDetail = spuDetailService.getById(id);
        if (spuDetail == null){
            throw new LyException(400,"商品id不存在！");
        }
        //转DTO
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetail);
        //设置属性
        spuDTO.setSpuDetail(spuDetailDTO);

        //4.查询categoryName和brandName
        handleBrandAndCategoryName(spuDTO);

        return spuDTO;
    }

    //商品修改
    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
//        - 1.判断参数中是否包含spu的Id
//        包含：需要修改spu；否则不需要修改
        Long spuId = spuDTO.getId();

        if (spuId != null){
            //包含，需要修改

            //DTO转PO
            Spu spu = spuDTO.toEntity(Spu.class);
            // 确保不更新saleable
            spu.setSaleable(null);
            boolean success = this.updateById(spu);
            if (!success){
                throw new LyException(500,"更新商品失败！");
            }
        }

//        - 2.判断是否包含spuDetail
//        包含：需要修改spuDetail，否则不需要修改
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        if (spuDetailDTO != null && spuDetailDTO.getSpuId()!=null){
            //DTO转PO
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            //包含：需要修改spuDetail
            boolean success = spuDetailService.updateById(spuDetail);
            if (!success){
                throw new LyException(500,"更新商品失败！");
            }
        }

//      - 3.判断是否包含sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
//        如果不包含sku，无需修改
        if (CollectionUtils.isEmpty(skuDTOList)){
            return;
        }

//       - 4.如果包含sku
//       - 判断是否包含saleable
        Map<Boolean, List<Sku>> skuMap =
                skuDTOList.stream()
                //DTO转PO
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                        //按照是否包含saleable进行分组
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));

        //- 包含saleable：就是需要删除的sku
        List<Sku> deleteSkuList = skuMap.get(true);
        //判断是否为空
        if (!CollectionUtils.isEmpty(deleteSkuList)){
            List<Long> deleteIds = deleteSkuList.stream().map(deleteSku -> deleteSku.getId()).collect(Collectors.toList());
            //批量删除
            skuService.removeByIds(deleteIds);
        }

        //- 不包含saleable：就是需要新增或修改的sku  - 包含id：修改  - 不包含id：新增
        List<Sku> saveOrUpdateSkuList = skuMap.get(false);

        //判断是否为空
        if (!CollectionUtils.isEmpty(saveOrUpdateSkuList)){
            //不为空，需要增或改
            skuService.saveOrUpdateBatch(saveOrUpdateSkuList);
        }

    }

    //根据spuId查询spu的所有规格参数键值对
    @Override
    public List<SpecParamDTO> querySpecsValues(Long spuId, Boolean searching) {
        //1.查询规格参数的key(spec_param)
        //获取商品对应的分类id
        Long categoryId = this.getById(spuId).getCid3();
        List<SpecParamDTO> specParamDTOList = specParamService.querySpecParams(categoryId, null, searching);

        //2.查询规格参数的value(spec_detail)
        //获取规格参数value的json字符串
        String specification = spuDetailService.getById(spuId).getSpecification();
        Map<Long, Object> valueMap = JsonUtils.toMap(specification, Long.class, Object.class);

        //给每个specParamDTO找到对应的value
        for (SpecParamDTO specParamDTO : specParamDTOList) {
            specParamDTO.setValue(valueMap.get(specParamDTO.getId()));
        }
        return specParamDTOList;
    }

    //查询categoryName和brandName
    private void handleBrandAndCategoryName(SpuDTO spuDTO) {

        //获取商品关联的三级的分类的id集合
        List<Long> categoryIds = spuDTO.getCategoryIds();
        //查询三级分类的集合
        List<Category> categoryList = categoryService.listByIds(categoryIds);

        //显示三级分类  拼接成下面的字符串样式  并用>连接
        // 家用电器>大家电>平板电视

        //方式一  字符串拼接
        /*StringBuilder sb = new StringBuilder();
        for (Category category : categoryList) {
            sb.append(category.getName()).append(">");
        }
        sb.deleteCharAt(sb.length()-1);
        spuDTO.setCategoryName(sb.toString());*/

        //方式二  流
        if (!CollectionUtils.isEmpty(categoryList)){
            String names = categoryList.stream().map(category -> category.getName()).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }

        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand != null){
            spuDTO.setBrandName(brand.getName());
        }
    }


}
